package network;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.KeyStore;
import java.util.List;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import log.Log;
import database.Individual;

public class Client extends Thread {

	private String username;
	private String password;
	private String keyStore;
	private String trustStore;
	private String host;
	private int port = 40000;
	private BufferedReader userIn = new BufferedReader(new InputStreamReader(
			System.in));
	private ObjectInputStream serverIn;
	private ObjectOutputStream serverOut;

	public Client(String host) {
		this.host = host;
		start();
	}

	public void run() {
		while (true) {
			try {
				System.out.println("---Login---");
				System.out.print("Username: ");
				username = userIn.readLine();
				System.out.print("Password: ");
				password = userIn.readLine();

				keyStore = "certificates/" + username + "KeyStore";
				trustStore = "certificates/" + username + "TrustStore";

				SSLSocket socket = authenticate();
				if (socket == null) {
					Log.log(Log.LOG_ERROR, "Wrong username or password!");
					continue;
				}
				initializeStreams(socket);

				System.out.println("Login Successful!");

				new Thread() {
					public void run() {
						Object obj;
						try {
							while ((obj = serverIn.readObject()) != null) {
								if (obj instanceof List) {
									List<?> list = (List<?>) obj;
									for (Object obj2 : list)
										System.out.println(obj2);
								} else {
									System.out.println(obj);
								}
							}
						} catch (Exception e) {
						}
					}
				}.start();

				String cmd;
				try {
					while (!(cmd = getCommand(userIn)).equals("exit")) {
						try {
							serverOut.writeObject(cmd);
							serverOut.flush();
						} catch (Exception e) {
							Log.log(Log.LOG_EXCEPTION, e.getMessage());
						}
					}
				} catch (NullPointerException e) {
				}

				try {
					serverIn.close();
					serverOut.close();
					socket.close();
					System.out.println("Logged out user.");
					System.out.println();
				} catch (IOException e) {
					Log.log(Log.LOG_EXCEPTION, e.getMessage());
				}
			} catch (IOException e) {
				Log.log(Log.LOG_ERROR, e.getMessage());
			}
		}
	}

	private void initializeStreams(SSLSocket socket) {
		try {
			serverOut = new ObjectOutputStream(socket.getOutputStream());
			serverIn = new ObjectInputStream(socket.getInputStream());
		} catch (IOException e) {
			Log.log(Log.LOG_ERROR, e.getMessage());
		}
	}

	private String getCommand(BufferedReader userIn) {
		try {
			return userIn.readLine();
		} catch (IOException e1) {
			Log.log(Log.LOG_EXCEPTION, e1.getMessage());
		}
		return null;
	}

	private SSLSocket authenticate() {
		SSLSocket socket = null;
		try {
			SSLContext context = SSLContext.getInstance("TLS");

			KeyManagerFactory keyManagerFactory = KeyManagerFactory
					.getInstance("SunX509");
			KeyStore keyKeyStore = KeyStore.getInstance("JKS");
			keyKeyStore.load(new FileInputStream(keyStore),
					password.toCharArray());

			TrustManagerFactory trustManagerFactory = TrustManagerFactory
					.getInstance("SunX509");
			KeyStore trustKeyStore = KeyStore.getInstance("JKS");
			trustKeyStore.load(new FileInputStream(trustStore),
					password.toCharArray());

			trustManagerFactory.init(trustKeyStore);
			keyManagerFactory.init(keyKeyStore, password.toCharArray());

			TrustManager[] trustManager = trustManagerFactory
					.getTrustManagers();
			context.init(keyManagerFactory.getKeyManagers(), trustManager, null);

			SSLSocketFactory factory = context.getSocketFactory();
			socket = (SSLSocket) factory.createSocket(host, port);

			String[] goodCiphers = { "SSL_RSA_WITH_RC4_128_SHA" };
			socket.setEnabledCipherSuites(goodCiphers);

			socket.startHandshake();

		} catch (Exception e) {
			Log.log(Log.LOG_EXCEPTION, e.getMessage());
		}
		return socket;
	}

	public static void main(String[] args) {
		if (args.length == 0)
			System.out.println("You need to enter hostname.");
		else
			new Client(args[0]);
	}

}
